﻿using System;
using Microsoft.Practices.Unity;
using NUnit.Framework;
using Sessionizer.Tests.Abstraction;

namespace Sessionizer.Tests.Core
{
    public abstract class SessionComponentResolutionTests : AbstractTest
    {
        protected override void FixtureConfigure(IIoCContainerBuilder container)
        {
 	        base.FixtureConfigure(container);
            container.RegisterType<IComponent, Component>();
            container.RegisterType<IDependency1, Dependency1>(LifetimeStyle.Session);
            container.RegisterType<IDependency2, Dependency2>(LifetimeStyle.Session);
            container.RegisterType<JustAClass>(LifetimeStyle.Session);
        }

        [Test]
        public void SameInstanceResolvedInSession()
        {
            using (var session = Container.Session())
            {
                using (session.Bind())
                {
                    var d2 = Container.Resolve<IDependency2>();
                    var resolved = Container.Resolve<IDependency2>();
                    Assert.IsTrue(ReferenceEquals(d2, resolved));
                }
            }
        }

        [Test]
        public void SessionBindingsSwitchesCurrentSession()
        {
            using (var session1 = Container.Session())
            {
                using (var session2 = Container.Session())
                {
                    IDependency2 d21;
                    IDependency2 d22;
                    using (session1.Bind())
                    {
                        d21 = Container.Resolve<IDependency2>();
                    }
                    using (session2.Bind())
                    {
                        d22 = Container.Resolve<IDependency2>();                                               
                    }
                    Assert.IsFalse(ReferenceEquals(d21, d22));

                    using (session1.Bind())
                    {                        
                        Assert.IsTrue(ReferenceEquals(d21, Container.Resolve<IDependency2>()));
                    }
                    using (session2.Bind())
                    {
                        Assert.IsTrue(ReferenceEquals(d22, Container.Resolve<IDependency2>()));
                    }
                }
            }
        }

        [Test]
        public void DirectResolveAndResolvedByComponentAreSame()
        {
            using (var session = Container.Session())
            {
                using (session.Bind())
                {
                    var depandency2 = Container.Resolve<IDependency2>();
                    var component = Container.Resolve<IComponent>();
                    Assert.IsTrue(ReferenceEquals(depandency2, component.D2));
                }
            }
        }

        [Test]
        public void ResolutionFailsOutsideSessionBinding()
        {
            using (var session = Container.Session())
            {
                using (session.Bind())
                {
                    try
                    {
                        Container.Resolve<IDependency2>();
                    }
                    catch
                    {
                        Assert.Fail();
                    }
                    
                }
                try
                {
                    var dependency2 = Container.Resolve<IDependency2>();
                    Assert.Fail();
                }
                catch
                {
                    Assert.Pass();
                }
                
            }
        }

        private class Component : IComponent
        {
            private readonly IDependency1 _d1;
            private readonly IDependency2 _d2;

            public Component(IDependency1 d1, IDependency2 d2)
            {
                _d1 = d1;
                _d2 = d2;
            }

            public IDependency1 D1
            {
                get { return _d1; }
            }

            public IDependency2 D2
            {
                get { return _d2; }
            }
        }


        private class Dependency1 : IDependency1
        {
        }

        private class Dependency2 : IDependency2
        {
        }

        private interface IComponent
        {
            IDependency1 D1 { get; }

            IDependency2 D2 { get; }
        }

        private interface IDependency1
        {
        }

        private interface IDependency2
        {
        }


        private class JustAClass
        {
        }



        [Test]
        public void TypeResolutionWorks()
        {
            using (var session = Container.Session())
            {
                using (session.Bind())
                {
                    var c1 = Container.Resolve<JustAClass>();
                    var c2 = Container.Resolve<JustAClass>();
                    Assert.IsTrue(ReferenceEquals(c1,c2));
                }
            }
        }
    }
}